﻿using System.Linq;
using CID.Domain.Exceptions;
using CID.Domain.Users;
using CID.Tests.Support;
using NUnit.Framework;

namespace CID.Domain.Tests.Users
{
    [TestFixture]
    public class UserTests : BaseFunctionalTests
    {
        private const string Name = "Name";
        private const string UserName = "UserName";
        private const string Email = "user@name.com";
        private User user = null;

        [SetUp]
        public override void SetUp()
        {
            base.SetUp();
            user = new User(Name, UserName, Email);
        }

        #region Constructor
        [Test]
        public void CreateNewUser()
        {
            var user = new User(Name,UserName, Email);

            Assert.AreEqual(Name, user.Name);
            Assert.AreEqual(UserName, user.UserName);
            Assert.AreEqual(Email, user.Email);
            Assert.IsTrue(user.Enabled);
            CollectionAssert.IsEmpty(user.AssignedRoles);
        }
        #endregion

        #region AssignRole
        [Test]
        public void AssignOneRole_AssignItOnce_ShouldSucceed()
        {
            var userRole = UserRole.Architect;

            user.AssignRole(userRole);

            CollectionAssert.AllItemsAreInstancesOfType(user.AssignedRoles, typeof(UserRoleAssignment));
            Assert.AreEqual(1, user.AssignedRoles.Count());
            Assert.AreEqual(1, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole)));
        }

        [Test]
        public void AssignOneRole_AssignItTwice_ShouldBeAddedOnlyOnce()
        {
            var userRole = UserRole.Architect;

            user.AssignRole(userRole);
            user.AssignRole(userRole);

            CollectionAssert.AllItemsAreInstancesOfType(user.AssignedRoles, typeof(UserRoleAssignment));
            Assert.AreEqual(1, user.AssignedRoles.Count());
            Assert.AreEqual(1, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole)));
        }

        [Test]
        public void AssignTwoRoles_AssignOnceEachOfThem_ShouldSucceed()
        {
            var userRole1 = UserRole.Architect;
            var userRole2 = UserRole.Developer;

            user.AssignRole(userRole1);
            user.AssignRole(userRole2);

            CollectionAssert.AllItemsAreInstancesOfType(user.AssignedRoles, typeof(UserRoleAssignment));
            Assert.AreEqual(2, user.AssignedRoles.Count());
            Assert.AreEqual(1, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole1)));
            Assert.AreEqual(1, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole2)));
        }

        [Test, ExpectedException(typeof(InvalidActionForDisabledObjectException))]
        public void AssignOneRole_UserDisabled_ShouldThrowException()
        {
            var userRole = UserRole.Architect;
            user.Enabled = false;

            user.AssignRole(userRole);
        }
        #endregion

        #region UnassignRole
        [Test]
        public void UnassignRole_RoleAssignedPreviously_ShouldSucceed()
        {
            var userRole1 = UserRole.Architect;
            var userRole2 = UserRole.Developer;
            user.AssignRole(userRole1);
            user.AssignRole(userRole2);

            user.UnassignRole(userRole1);

            Assert.AreEqual(1, user.AssignedRoles.Count());
            Assert.AreEqual(0, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole1)));
            Assert.AreEqual(1, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole2)));
        }

        [Test]
        public void UnassignRole_RoleNotAssignedPreviously_NothingShouldHappen()
        {
            var userRole1 = UserRole.Architect;
            var userRole2 = UserRole.Developer;
            var userRole3 = UserRole.Manager;
            user.AssignRole(userRole1);
            user.AssignRole(userRole2);

            user.UnassignRole(userRole3);

            Assert.AreEqual(2, user.AssignedRoles.Count());
            Assert.AreEqual(1, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole1)));
            Assert.AreEqual(1, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole2)));
            Assert.AreEqual(0, user.AssignedRoles.Count(x => x.UserRole.Equals(userRole3)));
        }

        [Test]
        public void UnassignRole_NoRolesAssigned_NothingShouldHappen()
        {
            var userRole = UserRole.Architect;

            user.UnassignRole(userRole);

            CollectionAssert.IsEmpty(user.AssignedRoles);
        }

        [Test, ExpectedException(typeof(InvalidActionForDisabledObjectException))]
        public void UnassignRole_UserDisabled_ShouldThrowException()
        {
            var userRole = UserRole.Architect;
            user.AssignRole(userRole);
            user.Enabled = false;

            user.UnassignRole(userRole);
        }
        #endregion

        #region Is
        [Test]
        public void Is_NoRolesAssigned_ShouldReturnFalse()
        {
            var userRole = UserRole.Architect;

            var result = user.Is(userRole);

            Assert.IsFalse(result);
        }

        [Test]
        public void Is_RolePreviouslyAssigned_ShouldReturnTrue()
        {
            var userRole1 = UserRole.Architect;
            var userRole2 = UserRole.Developer;
            user.AssignRole(userRole1);
            user.AssignRole(userRole2);

            Assert.IsTrue(user.Is(userRole1));
            Assert.IsTrue(user.Is(userRole2));
        }

        [Test]
        public void Is_RoleNotPreviouslyAssigned_ShouldReturnFalse()
        {
            var userRole1 = UserRole.Architect;
            var userRole2 = UserRole.Developer;
            user.AssignRole(userRole1);

            Assert.IsFalse(user.Is(userRole2));
        }
        #endregion
    }
}
